(function (factory) {
    if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
        factory(require("lego.tool"), require("knockout"), exports);
    } else if (typeof define === "function" && define["amd"]) {
        define(["lego.tool", "knockout", "exports"], factory);
    } else {
        factory(window.lego.tool, ko, ko.lego = {});
    }
}(function (legoTool, ko, exports) {
    if (typeof (ko) === 'undefined') {
        throw new Error('Knockout is required, please ensure it is loaded before loading this lego.ko.js plug-in');
    }

    ko.lego = exports;
    exports.templatePath = "src/lib/lego/template/";
    exports.renderDelay = 100;

    /**
     * 跳过绑定
     */
    ko.bindingHandlers.stopBinding = {
        init: function () {
            return {controlsDescendantBindings: true};
        }
    };

    /**
     * 重新绑定html，html内容中的knockout语法也将生效
     */
    ko.bindingHandlers.htmlWithBinding = {
        init: function () {
            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            ko.utils.setHtml(element, valueAccessor());
            ko.applyBindingsToDescendants(bindingContext.$module, element);
        }
    };

    var defaultParams = {
        base: {
            label: {
                value: ko.observable(),
                templatePath: 'base/label'
            },
            input: {
                value: ko.observable(),
                inputType: 'text',
                placeholder: '',
                autocomplete: 'off',
                verify: '',
                verifyType: '',
                readonly: false,
                templatePath: 'base/input'
            },
            button: {
                text: ko.observable(),
                css: ko.observable(),
                icon: ko.observable(),
                filter: '',
                isSubmit: false,
                templatePath: 'base/button',
                fnClickBtn: function (data, event) {    //绑定到按钮上的click事件
                },
                fnClick: function (data, event) {   //外部传递过来的按钮click处理事件
                }
            },
            select: {
                selectedValue: ko.observable(),
                name: ko.observable(),
                optionList: ko.observableArray(),
                filter: '',
                canSearch: true,
                customId: 'id',
                customValue: 'value',
                verify: '',
                verifyType: '',
                templatePath: 'base/select'
            },
            checkbox: {
                selectedValue: ko.observable(),
                option: ko.observable(),
                filter: '',
                checked: ko.observable(false),
                skin: ko.observable(),
                options: ko.observableArray(),
                switchText: '',
                customId: 'id',
                customValue: 'value',
                templatePath: 'base/checkbox'
            },
            radio: {
                selectedValue: ko.observable(),
                option: ko.observable(),
                filter: '',
                checked: ko.observable(false),
                customId: 'id',
                customValue: 'value',
                templatePath: 'base/radio'
            },
            textarea: {
                value: ko.observable(),
                placeholder: ko.observable(),
                verify: '',
                verifyType: '',
                readonly: false,
                templatePath: 'base/textarea'
            }
        }
    };

    ko.bindingHandlers.baseLabel = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            params = $.extend($.extend({}, defaultParams.base.label), params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");

            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.baseInput = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            params = $.extend($.extend({}, defaultParams.base.input), params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.baseButton = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            var tempParams = $.extend({}, defaultParams.base.button);
            tempParams.filter = legoTool.generateUUID();
            params = $.extend(tempParams, params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");

            if (params.isSubmit) {
                layui.form.on('submit(' + params.filter + ')', function (data) {
                    params.fnClick();
                    return false;
                });
            } else {
                params.fnClickBtn = params.fnClick;
            }

            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.baseSelect = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            var tempParams = $.extend({}, defaultParams.base.select);
            tempParams.filter = legoTool.generateUUID();
            params = $.extend(tempParams, params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            setTimeout(function () {
                layui.form.render('select');
            }, exports.renderDelay);

            if (ko.isObservable(params.optionList)) {
                params.optionList.subscribe(function (newValue) {
                    layui.form.render('select');
                });
            }

            if (ko.isObservable(params.selectedValue)) {
                params.selectedValue.subscribe(function (newValue) {
                    $("select[lay-filter='" + params.filter + "']").val(newValue && newValue[params.customId] || '');
                    layui.form.render('select');
                })
            }

            layui.form.on('select(' + params.filter + ')', function (data) {
                if (legoTool.isNotNull(data.value)) {
                    params.selectedValue(legoTool.findInArray(ko.unwrap(params.optionList), data.value, params.customId))
                } else {
                    params.selectedValue(null);
                }
            });

            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.baseCheckbox = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            var tempParams = $.extend({}, defaultParams.base.checkbox);
            tempParams.filter = legoTool.generateUUID();
            params = $.extend(tempParams, params);

            var type = 'checkbox';
            if (ko.unwrap(params.skin) == 'switch') {
                $.each(ko.unwrap(params.options), function (index, item) {
                    if (index != 0) {
                        params.switchText += '|';
                    }
                    params.switchText += item[params.customValue];
                });
                if (ko.unwrap(params.checked)) {
                    params.selectedValue(ko.unwrap(params.options)[0]);
                } else {
                    params.selectedValue(ko.unwrap(params.options)[1]);
                }
                type = 'switch';
            } else {
                if (ko.unwrap(params.checked)) {
                    params.selectedValue(ko.unwrap(params.option));
                }
            }

            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            setTimeout(function () {
                layui.form.render('checkbox');
            }, exports.renderDelay);

            layui.form.on(type + '(' + params.filter + ')', function (data) {
                if (type == 'checkbox') {
                    if (data.elem.checked) {
                        params.selectedValue(ko.unwrap(params.option));
                    } else {
                        params.selectedValue(undefined);
                    }
                } else if (type == 'switch') {
                    if (data.elem.checked) {
                        params.selectedValue(ko.unwrap(params.options)[0]);
                    } else {
                        params.selectedValue(ko.unwrap(params.options)[1]);
                    }
                }
            });

            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    var tempRadioGroup = {};
    ko.bindingHandlers.baseRadio = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            var tempParams = $.extend({}, defaultParams.base.radio);
            tempParams.filter = legoTool.generateUUID();
            params = $.extend(tempParams, params);

            if (tempRadioGroup[params.filter]) {
                tempRadioGroup[params.filter].push(params.option);
            } else {
                tempRadioGroup[params.filter] = [params.option];
            }

            if (ko.unwrap(params.checked)) {
                params.selectedValue(params.option);
            }

            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            setTimeout(function () {
                layui.form.render('radio');
            }, exports.renderDelay);

            layui.form.on('radio(' + params.filter + ')', function (data) {
                params.selectedValue(legoTool.findInArray(tempRadioGroup[params.filter], data.value, params.customId));
            });

            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.baseTextarea = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            params = $.extend($.extend({}, defaultParams.base.textarea), params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.formInput = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            var tempParams = {
                label: defaultParams.base.label,
                input: defaultParams.base.input,
                templatePath: 'form/input'
            };
            params = $.extend($.extend({}, tempParams), params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.formSelect = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            var tempParams = {
                label: defaultParams.base.label,
                select: defaultParams.base.select,
                templatePath: 'form/select'
            };
            params = $.extend($.extend({}, tempParams), params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.formTextarea = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            var tempParams = {
                label: defaultParams.base.label,
                textarea: defaultParams.base.textarea,
                templatePath: 'form/textarea'
            };
            params = $.extend($.extend({}, tempParams), params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };

    ko.bindingHandlers.formButtons = {
        init: function (element, valueAccessor) {
            var params = ko.unwrap(valueAccessor());
            var tempParams = {
                buttonArray: ko.observableArray(),
                templatePath: 'form/buttons'
            };
            params = $.extend($.extend({}, tempParams), params);
            ko.renderTemplate(exports.templatePath + params.templatePath, params, {}, element, "replaceNode");
            return {'controlsDescendantBindings': true};
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {

        }
    };
}));